let fs = require('fs');
let path = require('path');
let {ensureFolder} = require('../dist/operateFilesystem.js');
let Agency4api = require('../dist/agency4api.js');

const insertUrl = '/insert-agency4api';
module.exports = {
    /**
     * @param {*} proxy 原来的serve proxy
     * @param {*} acceptHosts 需要处理的host数组（localhost自动处理，不用管）
     * @param {*} initAgency4apiOptions 初始化所有agency4api实例的配置文件的options
     * @param {*} relativeFolder 保存配置文件的目录的绝对路径
     */
    getProxyConfig: function ({
        proxy,
        acceptHosts,
        initAgency4apiOptions = {},
        relativeFolder = path.join(process.cwd(), './agency4api')
    }) {
        acceptHosts = acceptHosts || [];
        if (!proxy) {
            throw `${ Agency4api.errorPre }getProxyConfig的参数option.proxy字段是必需有`;
        }
        ensureFolder(relativeFolder);

        let configJson = proxy;
        let backendPaths = Object.keys(configJson).map((item) => {
            let targetFolder = item.replace(/^[/\\]/, '').replace(/[^\w-]/g, '-');
            let configPath = path.join(relativeFolder, `customAgency4apiConfig-${ targetFolder }.json`);
            if (fs.existsSync(configPath)) {
                //如果已经存在，不进行初始化
                initAgency4apiOptions = {};
            }
            return {
                key: item,
                configPath,
                agency4api: new Agency4api({ // agency4api supports multi instances
                    configPath,
                    options: {
                        ...initAgency4apiOptions,
                        mockdataFolder: path.resolve(relativeFolder, `./mockdata/${ targetFolder }/`)
                    }
                }),
                proxy: configJson[item]
            };
        });

        let config = {// 使用代理
            proxy: {},
            apiStatus: Agency4api.apiStatus,
            extnameByBufferMap: Agency4api.extnameByBufferMap,
            instanceList: backendPaths
        };

        let insertProxy = {// 专门处理 agency4api 信息注入
            // 这里写了，不会实际用到，但不写会报错
            target: 'http://insert-agency4api/index',
            bypass: function (req, res) {
                if (res.finished || req.path.indexOf(insertUrl) < 0) { // 多个target会多次触发彼此的bypass
                    return;
                }
                let agency4apiList = [];
                let pathGroupsList = {};
                let autoAgencyList = {};
                let autoRefreshList = {};
                config.instanceList.forEach(({key, configPath}) => {
                    agency4apiList.push(key);

                    let config = require(configPath);
                    let configOptions = config.options;
                    pathGroupsList[key] = config.paths;
                    autoAgencyList[key] = configOptions.isAutoAgency;
                    autoRefreshList[key] = configOptions.isAutoRefresh;
                });

                let agencyImagesExtnameMap = config.extnameByBufferMap;

                res.status(200).json({
                    agency4apiInserted:
                        String(req.headers.host).startsWith('localhost') ||
                        acceptHosts.includes(req.headers.host),
                    agencyImagesExtnameMap: JSON.stringify(agencyImagesExtnameMap),
                    apiStatus: Object.keys(config.apiStatus).join(','),
                    agency4apiList: agency4apiList.join(','),
                    pathGroupsList: JSON.stringify(pathGroupsList),
                    autoAgencyList: JSON.stringify(autoAgencyList),
                    autoRefreshList: JSON.stringify(autoRefreshList),
                });
                res.end();
                // 一旦返回，直接跳过
                return false;
            },
            changeOrigin: true, // 是否允许切换域名 因为在代理不同域名，所以必须设置为true
            secure: false // 默认情况下，不接受运行在 HTTPS 上，且使用了无效证书的后端服务器；想接受设置为false
        };
        // 通过login代理，将信息注入到前台
        config.proxy[insertUrl] = insertProxy;

        backendPaths.forEach((item) => {
            if (item.proxy.ws) {
                require('../dist/proxy-ws').deal(item);
            }
            let agency4api = item.agency4api;
            let proxyKey = item.key;
            let configPath = item.configPath;
            config.proxy[proxyKey] = {
                ...item.proxy,
                // 自己处理返回
                selfHandleResponse: true,
                bypass: function (req, res) {
                    let keyPath = req.path;
                    // 某种原因导致已经 finished 或 当前路径不在规则内
                    if (res.finished || keyPath.indexOf(proxyKey) < 0) {
                        // 前端静态资源，不用代理
                        return;
                    }
                    let judgeFunc = function (str) {
                        return keyPath.replace(proxyKey, '').indexOf(str) === 0;
                    };
                    if (judgeFunc('/agency-config-query')) {// 查询配置文件
                        let apiData = null;
                        if (fs.existsSync(configPath)) {
                            apiData = fs.readFileSync(configPath).toString();
                        }
                        res.status(200).json({
                            success: !!apiData,
                            data: apiData
                        });
                        return;
                    } else if (judgeFunc('/agency-config-update')) {// 修改配置文件
                        let reqBody = [];
                        req.on('data', (chunk) => {
                            reqBody.push(chunk);
                        });
                        req.on('end', () => {
                            // 处理后的参数，直接保存在私有字段里面，后面可以直接使用
                            let {
                                data,
                            } = JSON.parse(Buffer.concat(reqBody).toString());
                            fs.writeFileSync(configPath, JSON.stringify(data, null, 2));

                            res.status(200).json({
                                message: '修改成功'
                            });
                        });
                        return;
                    } else if (judgeFunc('/agency-createApi')) {// 创建接口代理文件的接口
                        (function () {
                            let reqBody = [];
                            req.on('data', (chunk) => {
                                reqBody.push(chunk);
                            });
                            req.on('end', () => {
                                // 处理后的参数，直接保存在私有字段里面，后面可以直接使用
                                let {
                                    key,
                                    param,
                                    data,
                                    query,
                                    apiState,
                                    store,
                                    pathGroup
                                } = JSON.parse(Buffer.concat(reqBody).toString());

                                if (apiState !== 'onlyadd') {
                                    agency4api.setPaths(
                                        pathGroup || 'manual',
                                        key,
                                        apiState === 'forbidden' ? false : apiState
                                    );
                                }

                                if (apiState != null && apiState !== 'forbidden' && apiState !== Agency4api.apiStatus.folder) {
                                    let extname;
                                    // 数组，多半是文件的二进制
                                    let arr = /^\s*\[\s*(\d+)\s*,\s*(\d+)/.exec(data);
                                    if (arr) {
                                        extname = Agency4api.getExtnameByBuffer([arr[1], arr[2]]);
                                        if (extname) {
                                            data = Buffer.from(JSON.parse(data));
                                        } else {
                                            extname = 'json';
                                        }
                                    }
                                    agency4api.setApiData({
                                        extname,
                                        keyPath: key,
                                        query: query && JSON.parse(query),
                                        param,
                                        store,
                                        data: data
                                    });
                                }

                                res.status(200).json({
                                    message: '添加成功'
                                });
                                //代理失败（如：断网），系统会使用end，这样会报错
                                res.end = function (message) {
                                    console.error(message);
                                };
                            });
                        })();
                        return;
                    } else if (judgeFunc('/agency-queryApi')) {// 查询接口代理文件的接口
                        let apiData = agency4api.getApiData({key: req.query.key});

                        res.status(200).json({
                            success: !!apiData,
                            data: apiData
                        });
                        return false;
                    } else if (judgeFunc('/agency-queryInfoList')) {// 批量查询接口代理文件的接口
                        let apiData = agency4api.getApiDataListInfo({number: req.query.number || 100});

                        res.status(200).json({
                            success: !!apiData,
                            data: apiData
                        });
                        return false;
                    } else if (judgeFunc('/agency-modifyApi')) {// 修改接口代理文件的接口
                        let reqBody = [];
                        req.on('data', (chunk) => {
                            reqBody.push(chunk);
                        });
                        req.on('end', () => {
                            // 处理后的参数，直接保存在私有字段里面，后面可以直接使用
                            let {
                                key,
                                data,
                                store
                            } = JSON.parse(Buffer.concat(reqBody).toString());
                            agency4api.setApiData({key, data, store});
                            res.status(200).json({
                                message: '修改成功'
                            });
                            //代理失败（如：断网），会设置end报错
                            res.end = function (message) {
                                console.error(message);
                            };
                        });
                        return;
                    } else if (judgeFunc('/agency-recycleApi')) {// 缓存接口代理文件的接口
                        let message = '缓存成功';
                        try {
                            agency4api.recycleApiData({stemp: req.query.stemp});
                        } catch (e) {
                            message = '部分数据缓存失败';
                        }
                        res.status(200).json({message});
                        return false;
                    } else if (judgeFunc('/agency-delApi')) {// 删除接口代理文件的接口
                        let {key, keyPath, isClear, isClearAll, pathGroup} = req.query || {};

                        let json = {};
                        if (pathGroup) {
                            agency4api.clearPaths(pathGroup);
                            json.isSuccess = true;
                        } else if ((key || keyPath || isClear === 'true' || isClearAll === 'true') && agency4api.delApiData({
                            key,
                            keyPath,
                            isClear: String(isClear) === 'true',
                            isClearAll: String(isClearAll) === 'true'
                        })) {
                            json.isSuccess = true;
                        }
                        res.status(200).json(json);
                        return false;
                    } else if (judgeFunc('/agency-change-agency')) {// 切换代理状态
                        res.status(200).json({
                            isOpen: agency4api.changeAutoAgency()
                        });
                        return false;
                    } else if (judgeFunc('/agency-change-refresh')) {// 切换更新状态
                        res.status(200).json({
                            isOpen: agency4api.changeAutoRefresh()
                        });
                        return false;
                    }

                    if ((
                        //localhost必须处理
                        String(req.headers.host).startsWith('localhost')
                        ||
                        // 当前host不需要离线调试 acceptHosts为null代表都处理，否则需要在数组内
                        acceptHosts.includes(req.headers.host)
                    ) && agency4api.needAgencyApiData(keyPath)) {
                        let fn = function () {
                            const lastConfigOptions = agency4api.getLastConfigFile().options;
                            if (lastConfigOptions.statusCode) { // 如果错误设置了状态，直接返回，用来模拟 404、500 等错误情况
                                res.status(lastConfigOptions.statusCode);
                                res.end();
                            } else if (!lastConfigOptions.isAutoRefresh) {
                                let apiData = agency4api.getApiData({
                                    keyPath,
                                    param: req.__post_param__,
                                    query: req.query
                                });
                                let targetData = null;
                                if (apiData) {
                                    try {
                                        targetData = JSON.parse(apiData.data);
                                    } catch (e) {
                                        console.log(new Error('json 数据异常：' + keyPath));
                                    }
                                }
                                if (targetData) {
                                    // 不需要更新
                                    req.__no_refresh__ = true;

                                    // 设置了延时
                                    let delayTime = apiData.store?.delay;

                                    let fn = () => {
                                        if (delayTime) {
                                            res.end = res.__delayEnd;
                                        }
                                        if (apiData.extname === 'json') {
                                            res.json(targetData);
                                        } else {
                                            res.send(Buffer.from(targetData));
                                        }
                                        res.end();
                                        //代理失败（如：断网），系统会使用end，这样会报错
                                        res.end = function (message) {
                                            console.error(message);
                                        };
                                    };

                                    res.status(200);
                                    if (delayTime) {
                                        res.__delayEnd = res.end;
                                        res.end = function (message) {
                                            console.log(message);
                                        };

                                        setTimeout(() => {
                                            fn();
                                        }, delayTime * 1000 || 0);
                                    } else {
                                        fn();
                                    }
                                    return false;
                                }
                            }
                        };
                        // 代理时，不要gzip等压缩，否则处理返回数据时会是压缩过的，太麻烦
                        req.headers['accept-encoding'] = null;
                        // 强制不缓存，以免返回304，导致保存的数据异常
                        delete req.headers['if-none-match'];
                        if (/post/i.test(req.method)) {// post参数获取
                            let reqBody = [];
                            req.on('data', (chunk) => {
                                reqBody.push(chunk);
                            });
                            req.on('end', () => {
                                // 处理后的参数，直接保存在私有字段里面，后面可以直接使用
                                req.__post_param__ = Buffer.concat(reqBody).toString();
                                fn();
                            });
                        } else {
                            //get方式，可以直接跳过
                            return fn();
                        }
                    } else {
                    }
                },
                onProxyRes: function (proxyRes, req, res) {
                    let statusCode = proxyRes.statusCode;
                    // res.finished === true 说明已经是返回的代理数据
                    let isHTTPSuccess = (statusCode >= 200 && statusCode < 300) || statusCode === 304;
                    //原始url，因为可能使用proxy.pathRewrite
                    let originalPath = req.originalUrl.split('?')[0];

                    if (!res.finished && !req.__no_refresh__) {
                        if (!isHTTPSuccess) {
                            res.status(statusCode);
                            res.send();
                        } else if (isHTTPSuccess) {
                            let bufferList = [];
                            proxyRes.on('data', (chunk) => {
                                bufferList.push(chunk);
                            });
                            proxyRes.on('end', () => {
                                let targetBuffer = Buffer.concat(bufferList);
                                let extname = null;

                                let isJson = proxyRes.headers["content-type"]?.includes('application/json');
                                let targetData = null;
                                if (isJson) {
                                    extname = 'json';
                                    targetData = targetBuffer.toString();
                                } else {
                                    extname = Agency4api.getExtnameByBuffer(targetBuffer);
                                    targetData = targetBuffer;
                                }

                                //目前这里 支持json 和 二进制
                                res.status(200);
                                if (isJson) {
                                    try {
                                        res.json(JSON.parse(targetData));
                                    } catch (e) { // 某种情况下，打印路径，方便定位异常
                                        console.log(originalPath);
                                        throw e;
                                    }
                                } else {
                                    res.send(Buffer.from(targetData));
                                }

                                if (extname) {
                                    try {// 请求成功
                                        // 如果是post，参数之前已经拿到了，直接取出来
                                        let postParam = req.__post_param__;
                                        targetData && agency4api.setApiData({
                                            extname,
                                            keyPath: originalPath,
                                            query: req.query,
                                            param: postParam,
                                            data: targetData
                                        });
                                    } catch (e) {
                                        console.log(originalPath, e);
                                    }
                                }
                            });
                        }
                    }
                }
            };
        });
        return config;
    },
    /**
     * 通过匹配规则，获取具体的webpack.rules。
     * 通过此方法，注入 agency4api 的信息到指定文件
     * @param {*} testList 文件匹配规则集合
     * @returns 
     */
    getInsertRules: function (testList = [], getOptions) {
        getOptions = getOptions || function() {
            return {
                prepend: `require('agency4api/development.js');`,
                append: ''
            }
        };
        return testList.map((item) => {
            return {
                // 单独配置一个文件
                test: item,
                use: [
                    {
                        loader: path.join(__dirname, './webpack-adjust-loader.js'),
                        options: getOptions(item)
                    }
                ]
            };
        });
    }
};
